home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
ohlcpio.zip
/
COPYIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-07
|
16KB
|
580 lines
/* copyin.c - cpio copy in sub-function.
Copyright (C) 1988, 1989, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef S_IFLNK
#define lstat stat
#endif
#include <errno.h>
extern int errno;
#include <fcntl.h>
#include <sys/file.h>
#ifdef USG
#include <time.h>
#include <string.h>
#include <sys/sysmacros.h>
#else
#include <sys/time.h>
#include <strings.h>
#endif
#include "cpio.h"
#include "dstring.h"
#include "extern.h"
void bcopy ();
void read_in_ascii ();
void read_in_binary ();
void mode_string ();
void print_name_with_quoting ();
void swab_array ();
/* Return 16-bit integer I with the bytes swapped. */
#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff))
/* Read header, including the name of the file, from file
descriptor IN_DES into FILE_HDR. */
void
read_in_header (file_hdr, in_des)
struct cpio_header *file_hdr;
int in_des;
{
long bytes_skipped = 0; /* Bytes of junk found before magic number. */
/* Search for valid magic number. */
copy_in_buf ((char *) file_hdr, in_des, 6);
while (1)
{
if (portability_flag && !strncmp ((char *) file_hdr, "070707", 6))
{
if (bytes_skipped > 0)
error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
read_in_ascii (file_hdr, in_des);
break;
}
if (binary_flag
&& (file_hdr->h_magic == 070707
|| file_hdr->h_magic == swab_short ((unsigned short) 070707)))
{
/* Having to skip 1 byte because of word alignment is normal. */
if (bytes_skipped > 1)
error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
read_in_binary (file_hdr, in_des);
break;
}
bytes_skipped++;
bcopy ((char *) file_hdr + 1, (char *) file_hdr, 5);
copy_in_buf ((char *) file_hdr + 5, in_des, 1);
}
}
/* Fill in FILE_HDR by reading an ASCII format cpio header from
file descriptor IN_DES, except for the magic number, which is
already filled in. */
void
read_in_ascii (file_hdr, in_des)
struct cpio_header *file_hdr;
int in_des;
{
char ascii_header[78];
copy_in_buf (ascii_header, in_des, 70);
ascii_header[70] = '\0';
sscanf (ascii_header,
"%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
&file_hdr->h_dev, &file_hdr->h_ino,
&file_hdr->h_mode, &file_hdr->h_uid, &file_hdr->h_gid,
&file_hdr->h_nlink, &file_hdr->h_rdev, &file_hdr->h_mtime,
&file_hdr->h_namesize, &file_hdr->h_filesize);
/* Read file name from input. */
if (file_hdr->h_name != NULL)
free (file_hdr->h_name);
file_hdr->h_name = (char *) xmalloc (file_hdr->h_namesize);
copy_in_buf (file_hdr->h_name, in_des, file_hdr->h_namesize);
}
/* Fill in FILE_HDR by reading a binary format cpio header from
file descriptor IN_DES, except for the first 6 bytes, which are
already filled in. */
void
read_in_binary (file_hdr, in_des)
struct cpio_header *file_hdr;
int in_des;
{
copy_in_buf ((char *) file_hdr + 6, in_des, 20);
/* If correct magic number but byte swapped, fix the header. */
if (file_hdr->h_magic == swab_short ((unsigned short) 070707))
{
static int warned = 0;
/* Alert the user that they might have to do byte swapping on
the file contents. */
if (warned == 0)
{
error (0, 0, "warning: archive header has reverse byte-order");
warned = 1;
}
swab_array ((short *) file_hdr, 13);
}
file_hdr->h_mtime = file_hdr->h_mtimes[0] << 16 | file_hdr->h_mtimes[1];
file_hdr->h_filesize = file_hdr->h_filesizes[0] << 16
| file_hdr->h_filesizes[1];
/* Read file name from input. */
if (file_hdr->h_name != NULL)
free (file_hdr->h_name);
file_hdr->h_name = (char *) xmalloc (file_hdr->h_namesize);
copy_in_buf (file_hdr->h_name, in_des, file_hdr->h_namesize);
/* In binary mode, the amount of space allocated in the header for
the filename is `h_namesize' rounded up to the next short-word,
so we might need to drop a byte. */
if (file_hdr->h_namesize % 2)
toss_input (in_des, 1);
}
/* Exchange the bytes of each element of the array of COUNT shorts
starting at PTR. */
void
swab_array (ptr, count)
short *ptr;
int count;
{
while (count-- > 0)
{
*ptr = swab_short (*ptr);
++ptr;
}
}
/* Current time for verbose table. */
static long current_time;
/* Read the collection from standard input and create files
in the file system. */
void
process_copy_in ()
{
char done = FALSE; /* True if trailer reached. */
int res; /* Result of various function calls. */
dynamic_string new_name; /* New file name for rename option. */
FILE *tty_in; /* Interactive file for rename option. */
FILE *tty_out; /* Interactive file for rename option. */
char *str_res; /* Result for string function. */
long times[2]; /* For setting file times. */
struct stat file_stat; /* Output file stat record. */
struct cpio_header file_hdr; /* Output header information. */
int out_file_des; /* Output file descriptor. */
int in_file_des; /* Input file descriptor. */
char skip_file; /* Flag for use with patterns. */
int i; /* Loop index variable. */
char *link_name = NULL; /* Name of hard and symbolic links. */
/* Initialize copy in. */
file_hdr.h_name = NULL;
ds_init (&new_name, 128);
/* Open interactive file pair for rename operation. */
if (rename_flag)
{
tty_in = fopen ("/dev/tty", "r");
if (tty_in == NULL)
error (2, errno, "/dev/tty");
tty_out = fopen ("/dev/tty", "w");
if (tty_out == NULL)
error (2, errno, "/dev/tty");
}
/* Get date and time if needed for processing the table option. */
if (table_flag && verbose_flag)
time (¤t_time);
/* Check whether the input file might be a tape. */
in_file_des = fileno (stdin);
if (fstat (in_file_des, &file_stat))
error (1, errno, "standard input is closed");
input_is_special = ((file_stat.st_mode & S_IFMT) == S_IFCHR
|| (file_stat.st_mode & S_IFMT) == S_IFBLK);
input_is_seekable = ((file_stat.st_mode & S_IFMT) == S_IFREG);
output_is_seekable = TRUE;
/* While there is more input in collection, process the input. */
while (!done)
{
/* Start processing the next file by reading the header. */
read_in_header (&file_hdr, in_file_des);
/* Is this the header for the TRAILER file? */
if (strcmp ("TRAILER!!!", file_hdr.h_name) == 0)
{
done = TRUE;
break;
}
/* Does the file name match one of the given patterns? */
if (num_patterns <= 0)
skip_file = FALSE;
else
{
skip_file = copy_matching_files;
for (i = 0; i < num_patterns
&& skip_file == copy_matching_files; i++)
{
if (glob_match (save_patterns[i], file_hdr.h_name, 0) == 1)
skip_file = !copy_matching_files;
}
}
if (skip_file)
toss_input (in_file_des, file_hdr.h_filesize);
else if (table_flag)
{
if (verbose_flag)
{
#ifdef S_IFLNK
if ((file_hdr.h_mode & S_IFMT) == S_IFLNK)
{
link_name = (char *) xmalloc (file_hdr.h_filesize + 1);
link_name[file_hdr.h_filesize] = '\0';
copy_in_buf (link_name, in_file_des, file_hdr.h_filesize);
long_format (&file_hdr, link_name);
free (link_name);
file_hdr.h_filesize = 0;
}
else
#endif
long_format (&file_hdr, (char *) 0);
}
else
printf ("%s\n", file_hdr.h_name);
toss_input (in_file_des, file_hdr.h_filesize);
}
else
{
/* Copy the input file into the directory structure. */
/* Do we need to rename the file? */
if (rename_flag)
{
fprintf (tty_out, "rename %s -> ", file_hdr.h_name);
fflush (tty_out);
str_res = ds_fgets (tty_in, &new_name);
if (str_res == NULL || str_res[0] == 0)
{
toss_input (in_file_des, file_hdr.h_filesize);
continue;
}
else
file_hdr.h_name = copystring (new_name.ds_string);
}
/* See if the file already exists. */
if (lstat (file_hdr.h_name, &file_stat) == 0)
{
if (!unconditional_flag
&& file_hdr.h_mtime < file_stat.st_mtime)
{
error (0, 0, "%s not created: newer version exists",
file_hdr.h_name);
toss_input (in_file_des, file_hdr.h_filesize);
continue; /* Go to the next file. */
}
else if ((file_stat.st_mode & S_IFMT) == S_IFDIR)
{
error (0, 0, "cannot remove current %s: Is a directory",
file_hdr.h_name);
toss_input (in_file_des, file_hdr.h_filesize);
continue; /* Go to the next file. */
}
else if (unlink (file_hdr.h_name))
{
error (0, errno, "cannot remove current %s",
file_hdr.h_name);
toss_input (in_file_des, file_hdr.h_filesize);
continue; /* Go to the next file. */
}
}
/* Do the real copy or link. */
switch (file_hdr.h_mode & S_IFMT)
{
case S_IFREG:
/* Can the current file be linked to a previously copied file? */
if (file_hdr.h_nlink > 1)
{
link_name = find_inode_file (file_hdr.h_ino);
if (link_name == NULL)
add_inode (file_hdr.h_ino, file_hdr.h_name);
else
{
res = link (link_name, file_hdr.h_name);
if (res < 0 && create_dir_flag)
{
create_all_directories (file_hdr.h_name);
res = link (link_name, file_hdr.h_name);
}
if (res == 0)
{
if (verbose_flag)
error (0, 0, "%s linked to %s",
link_name, file_hdr.h_name);
toss_input (in_file_des, file_hdr.h_filesize);
}
else
link_name = NULL;
}
}
/* If not linked, copy the contents of the file. */
if (link_name == NULL)
{
out_file_des = open (file_hdr.h_name,
O_CREAT | O_WRONLY, 0600);
if (out_file_des < 0 && create_dir_flag)
{
create_all_directories (file_hdr.h_name);
out_file_des = open (file_hdr.h_name,
O_CREAT | O_WRONLY, 0600);
}
if (out_file_des < 0)
{
error (0, errno, "%s", file_hdr.h_name);
toss_input (in_file_des, file_hdr.h_filesize);
continue;
}
copy_files (in_file_des, out_file_des, file_hdr.h_filesize);
empty_output_buffer (out_file_des);
finish_output_file (file_hdr.h_name, out_file_des);
close (out_file_des);
/* File is now copied; set attributes. */
if (chmod (file_hdr.h_name, file_hdr.h_mode) < 0)
error (0, errno, "%s", file_hdr.h_name);
if (chown (file_hdr.h_name, file_hdr.h_uid,
file_hdr.h_gid) < 0
&& errno != EPERM)
error (0, errno, "%s", file_hdr.h_name);
if (retain_time_flag)
{
times[0] = times[1] = file_hdr.h_mtime;
if (utime (file_hdr.h_name, times) < 0)
error (0, errno, "%s", file_hdr.h_name);
}
}
break;
case S_IFDIR:
res = mkdir (file_hdr.h_name, file_hdr.h_mode);
if (res < 0 && create_dir_flag)
{
create_all_directories (file_hdr.h_name);
res = mkdir (file_hdr.h_name, file_hdr.h_mode);
}
if (res < 0)
{
error (0, errno, "%s", file_hdr.h_name);
continue;
}
if (chown (file_hdr.h_name, file_hdr.h_uid,
file_hdr.h_gid) < 0
&& errno != EPERM)
error (0, errno, "%s", file_hdr.h_name);
break;
case S_IFCHR:
case S_IFBLK:
#ifdef S_IFSOCK
case S_IFSOCK:
#endif
#ifdef S_IFIFO
case S_IFIFO:
#endif
res = mknod (file_hdr.h_name, file_hdr.h_mode, file_hdr.h_rdev);
if (res < 0 && create_dir_flag)
{
create_all_directories (file_hdr.h_name);
res = mknod (file_hdr.h_name, file_hdr.h_mode,
file_hdr.h_rdev);
}
if (res < 0)
{
error (0, errno, "%s", file_hdr.h_name);
continue;
}
if (chown (file_hdr.h_name, file_hdr.h_uid,
file_hdr.h_gid) < 0
&& errno != EPERM)
error (0, errno, "%s", file_hdr.h_name);
break;
#ifdef S_IFLNK
case S_IFLNK:
{
link_name = (char *) xmalloc (file_hdr.h_filesize + 1);
link_name[file_hdr.h_filesize] = '\0';
copy_in_buf (link_name, in_file_des, file_hdr.h_filesize);
res = symlink (link_name, file_hdr.h_name);
if (res < 0 && create_dir_flag)
{
create_all_directories (file_hdr.h_name);
res = symlink (link_name, file_hdr.h_name);
}
if (res < 0)
{
error (0, errno, "%s", file_hdr.h_name);
free (link_name);
continue;
}
free (link_name);
}
break;
#endif
default:
error (0, 0, "%s: unknown file type", file_hdr.h_name);
toss_input (in_file_des, file_hdr.h_filesize);
}
if (verbose_flag)
fprintf (stderr, "%s\n", file_hdr.h_name);
}
}
res = (input_bytes + io_block_size - 1) / io_block_size;
if (res == 1)
fprintf (stderr, "1 block\n");
else
fprintf (stderr, "%d blocks\n", res);
}
/* Print the file described by FILE_HDR in long format.
If LINK_NAME is nonzero, it is the name of the file that
this file is a symbolic link to. */
void
long_format (file_hdr, link_name)
struct cpio_header *file_hdr;
char *link_name;
{
char mbuf[11];
char tbuf[40];
long when;
mode_string (file_hdr->h_mode, mbuf);
mbuf[10] = '\0';
/* Get time values ready to print. */
when = file_hdr->h_mtime;
strcpy (tbuf, ctime (&when));
if (current_time - when > 6L * 30L * 24L * 60L * 60L
|| current_time - when < 0L)
{
/* The file is older than 6 months, or in the future.
Show the year instead of the time of day. */
strcpy (tbuf + 11, tbuf + 19);
}
tbuf[16] = '\0';
printf ("%s %3u ", mbuf, file_hdr->h_nlink);
if (numeric_uid)
printf ("%-8u %-8u ", file_hdr->h_uid, file_hdr->h_gid);
else
printf ("%-8.8s %-8.8s ", getuser (file_hdr->h_uid),
getgroup (file_hdr->h_gid));
if ((file_hdr->h_mode & S_IFMT) == S_IFCHR
|| (file_hdr->h_mode & S_IFMT) == S_IFBLK)
printf ("%3u, %3u ", major (file_hdr->h_rdev),
minor (file_hdr->h_rdev));
else
printf ("%8u ", file_hdr->h_filesize);
printf ("%s ", tbuf + 4);
print_name_with_quoting (file_hdr->h_name);
if (link_name)
{
printf (" -> ");
print_name_with_quoting (link_name);
}
putc ('\n', stdout);
}
void
print_name_with_quoting (p)
register char *p;
{
register unsigned char c;
while (c = *p++)
{
switch (c)
{
case '\\':
printf ("\\\\");
break;
case '\n':
printf ("\\n");
break;
case '\b':
printf ("\\b");
break;
case '\r':
printf ("\\r");
break;
case '\t':
printf ("\\t");
break;
case '\f':
printf ("\\f");
break;
case ' ':
printf ("\\ ");
break;
case '"':
printf ("\\\"");
break;
default:
if (c > 040 && c < 0177)
putchar (c);
else
printf ("\\%03o", (unsigned int) c);
}
}
}